GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#199)
by joseph
21:04
created

OverridesUpdateCommand::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
ccs 0
cts 4
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\Command;
4
5
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\PostProcessor\FileOverrider;
6
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
7
use Symfony\Component\Console\Helper\Table;
8
use Symfony\Component\Console\Input\InputInterface;
9
use Symfony\Component\Console\Input\InputOption;
10
use Symfony\Component\Console\Output\OutputInterface;
11
use Symfony\Component\Console\Style\SymfonyStyle;
12
13
class OverridesUpdateCommand extends AbstractCommand
14
{
15
    public const OPT_OVERRIDE_ACTION       = 'action';
16
    public const OPT_OVERRIDE_ACTION_SHORT = 'a';
17
18
    public const ACTION_TO_PROJECT   = 'toProject';
19
    public const ACTION_FROM_PROJECT = 'fromProject';
20
21
    /**
22
     * @var FileOverrider
23
     */
24
    protected $fileOverrider;
25
26
    public function __construct(FileOverrider $fileOverrider, ?string $name = null)
27
    {
28
        parent::__construct($name);
29
        $this->fileOverrider = $fileOverrider;
30
    }
31
32
    protected function execute(InputInterface $input, OutputInterface $output): void
33
    {
34
        $symfonyStyle = new SymfonyStyle($input, $output);
35
        $this->checkOptions($input);
36
        $output->writeln(
37
            '<comment>Updating overrides ' . $input->getOption(self::OPT_OVERRIDE_ACTION) . '</comment>'
38
        );
39
        $this->checkOptions($input);
40
        $this->fileOverrider->setPathToProjectRoot($input->getOption(self::OPT_PROJECT_ROOT_PATH));
41
        switch ($input->getOption(self::OPT_OVERRIDE_ACTION)) {
42
            case self::ACTION_TO_PROJECT:
43
                $this->actionOverridesToProject($symfonyStyle, $output);
44
45
                return;
46
            case self::ACTION_FROM_PROJECT:
47
                $this->actionOverridesFromProject($symfonyStyle, $output);
48
49
                return;
50
            default:
51
                throw new \InvalidArgumentException(
52
                    ' Invalid action ' . $input->getOption(self::OPT_OVERRIDE_ACTION)
53
                );
54
        }
55
    }
56
57
    private function actionOverridesToProject(SymfonyStyle $symfonyStyle, OutputInterface $output): void
58
    {
59
        $invalidOverrides = $this->fileOverrider->getInvalidOverrides();
60
        if ([] !== $invalidOverrides) {
61
            $symfonyStyle->error('Some Overrides are Invalid');
62
            $symfonyStyle->note(<<<TEXT
63
                    
64
If you want to reset everything, you should do the following:
65
66
    [ctrl] + [c]
67
    git add -A :/
68
    git reset --hard HEAD
69
70
TEXT
71
            );
72
            $fixed = $this->renderInvalidOverrides($invalidOverrides, $output, $symfonyStyle);
73
            if (false === $fixed) {
74
                throw new \RuntimeException('Errors in applying overrides');
75
            }
76
        }
77
        $this->renderTableOfUpdatedFiles($this->fileOverrider->applyOverrides(), $output);
78
        $output->writeln('<info>Overrides have been applied to project</info>');
79
    }
80
81
    private function renderInvalidOverrides(
82
        array $invalidOverrides,
83
        OutputInterface $output,
84
        SymfonyStyle $symfonyStyle
85
    ): bool {
86
        $return = false;
87
        foreach ($invalidOverrides as $pathToFileInOverrides => $details) {
88
            $return = $this->processInvalidOverride($pathToFileInOverrides, $details, $output, $symfonyStyle);
89
        }
90
91
        return $return;
92
    }
93
94
    private function processInvalidOverride(
95
        string $relativePathToFileInOverrides,
96
        array $details,
97
        OutputInterface $output,
98
        SymfonyStyle $symfonyStyle
99
    ): bool {
100
        $symfonyStyle->title('Working on ' . basename($relativePathToFileInOverrides));
101
        $symfonyStyle->newLine();
102
        $this->renderKeyValue(
103
            [
104
                'Project File'  => $details['projectPath'],
105
                'Override File' => $details['overridePath'],
106
                'New MD5'       => $details['new md5'],
107
                'Diff Size'     => substr_count($details['diff'], "\n"),
108
            ],
109
            $symfonyStyle
110
        );
111
        $output->writeln(<<<TEXT
112
        
113
<info>The suggested fix in this situation is:</info>
114
115
 * Rename the current override
116
 * Make a new override from the newly generated file 
117
 * Reapply your custom code to the project file
118
 * Finally delete the old override.
119
 
120
TEXT
121
        );
122
        if (!$symfonyStyle->ask('Would you like to move the current override and make a new one and then diff this?',
123
                                true)) {
124
            $output->writeln('<commment>Skipping ' . $relativePathToFileInOverrides . '</commment>');
125
126
            return false;
127
        }
128
129
        $symfonyStyle->section('Recreating Override');
130
        list($old, $new) = $this->fileOverrider->recreateOverride($relativePathToFileInOverrides);
131
        $this->renderKeyValue(
132
            [
133
                'Old Override' => $old,
134
                'New Override' => $new,
135
            ],
136
            $symfonyStyle
137
        );
138
        $projectRoot = $this->fileOverrider->getPathToProjectRoot();
139
        $output->writeln(<<<TEXT
140
        
141
Now we have created a new override from your freshly generated file, 
142
you need to manually copy across all the required changes from the old override into your project file.
143
144
Run this command <comment>in another terminal</comment>:
145
146
    cd $projectRoot
147
    
148
    meld .$new .$old && rm -f .$old
149
 
150
TEXT
151
        );
152
        $symfonyStyle->caution('You must do this bit really carefully and exactly as instructed!!');
153
154
        while (
155
            false === $symfonyStyle->confirm(
156
                'Confirm you have now copied all required changes from the old override to the new one?',
157
                false
158
            )
159
        ) {
160
            $symfonyStyle->warning('You must now copy all required changes from the old override to the new one');
161
        }
162
        $symfonyStyle->success("\n\nCompleted override update for $relativePathToFileInOverrides\n\n");
163
164
        return true;
165
    }
166
167
    private function renderKeyValue(array $keysToValues, SymfonyStyle $symfonyStyle): void
168
    {
169
        $symfonyStyle->newLine();
170
        $longestKey = max(array_map('strlen', array_keys($keysToValues)));
171
        foreach ($keysToValues as $key => $value) {
172
            $key = str_pad($key, $longestKey, ' ');
173
            $symfonyStyle->writeln("<comment>$key:</comment> $value");
174
        }
175
        $symfonyStyle->newLine();
176
    }
177
178
    private function renderTableOfUpdatedFiles(array $files, OutputInterface $output): void
179
    {
180
        list($updated, $same) = $files;
181
        if ([] !== $updated) {
182
            $output->writeln('Files Updated:');
183
            $table = new Table($output);
184
            foreach ($updated as $file) {
185
                $table->addRow([$file]);
186
            }
187
            $table->render();
188
        }
189
        if ([] !== $same) {
190
            $output->writeln('Files Same:');
191
            $table = new Table($output);
192
            foreach ($same as $file) {
193
                $table->addRow([$file]);
194
            }
195
            $table->render();
196
        }
197
    }
198
199
    private function actionOverridesFromProject(SymfonyStyle $symfonyStyle, OutputInterface $output): void
200
    {
201
        list($filesDifferent,) = $this->fileOverrider->compareOverridesWithProject();
202
        if ([] === $filesDifferent) {
203
            $symfonyStyle->success('All override files are up to date, nothing else required');
204
205
            return;
206
        }
207
        $symfonyStyle->note(<<<TEXT
208
209
Some override files are not up to date with project file changes.
210
    
211
What we need to do now is to update the override files with the changes you have made in your project files.                
212
               
213
TEXT
214
        );
215
        $action = $symfonyStyle->choice(
216
            'How would you like to resolve this?',
217
            [
218
                'process'            => 'Process each file one at a time and decide to copy or not',
219
                'copyAllFromProject' => 'Update all override files with the content of the project files',
220
                'skipAll'            => 'Do not update any override files and lose all changes on project files (danger)',
221
            ],
222
            'Process each file one at a time and decide to copy or not'
223
        );
224
        switch ($action) {
225
            case 'copyAllFromProject':
226
                $toUpdate = $filesDifferent;
227
                break;
228
            case 'skipAll':
229
                $toUpdate = [];
230
                break;
231
            case 'process':
232
                $toUpdate = $this->processFilesChanges($filesDifferent, $symfonyStyle, $output);
233
                break;
234
        }
235
236
        if ([] === $toUpdate) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $toUpdate does not seem to be defined for all execution paths leading up to this point.
Loading history...
237
            $symfonyStyle->success('No updates to apply');
238
239
            return;
240
        }
241
        $this->renderTableOfUpdatedFiles($this->fileOverrider->updateOverrideFiles($toUpdate), $output);
242
        $output->writeln('<info>Overrides have been updated from the project</info>');
243
    }
244
245
    private function processFilesChanges(
246
        array $filesDifferent,
247
        SymfonyStyle $symfonyStyle,
248
        OutputInterface $output
249
    ): array {
250
        $toUpdate = [];
251
        foreach ($filesDifferent as $relativePathToFileInProject => $details) {
252
            $symfonyStyle->section('Processing ' . $relativePathToFileInProject);
253
//            $table = new Table($output);
254
//            $table->setHeaders(['Key', 'Value']);
255
//            $table->addRows(
256
//                [
257
//                    ['Project File', $relativePathToFileInProject],
258
//                    ['Override File', $details['overridePath']],
259
//                    ['Diff Size', substr_count($details['diff'], "\n")],
260
//                ]
261
//            );
262
//            $table->render();
263
            $this->renderKeyValue(
264
                [
265
                    'Project File'  => $relativePathToFileInProject,
266
                    'Override File' => $details['overridePath'],
267
                    'Diff Size'     => substr_count($details['diff'], "\n"),
268
                ],
269
                $symfonyStyle
270
            );
271
            $output->writeln('<info>Diff:</info>');
272
            $output->write($details['diff']);
273
            $output->writeln("\n\n");
274
            if (true === $symfonyStyle->ask(
275
                    'Would you like to copy the project file contents into the override file?',
276
                    true
277
                )
278
            ) {
279
                $symfonyStyle->success(
280
                    'adding ' . $relativePathToFileInProject .
281
                    ' to list of files that will be copied into the overrides'
282
                );
283
                $toUpdate[$relativePathToFileInProject] = true;
284
                continue;
285
            }
286
            $symfonyStyle->note(
287
                'skipping ' . $relativePathToFileInProject
288
                . ' from list of files that will be copied into the overrides'
289
            );
290
291
        }
292
293
        return $toUpdate;
294
    }
295
296
    /**
297
     * @throws DoctrineStaticMetaException
298
     */
299
    protected function configure(): void
300
    {
301
        try {
302
            $this
303
                ->setName(AbstractCommand::COMMAND_PREFIX . 'overrides:update')
304
                ->setDefinition(
305
                    [
306
                        new InputOption(
307
                            self::OPT_OVERRIDE_ACTION,
308
                            self::OPT_OVERRIDE_ACTION_SHORT,
309
                            InputOption::VALUE_REQUIRED,
310
                            'One of [ fromProject,  toProject ]'
311
                        ),
312
                        $this->getProjectRootPathOption(),
313
                    ]
314
                )->setDescription(
315
                    'Update project overrides'
316
                );
317
        } catch (\Exception $e) {
318
            throw new DoctrineStaticMetaException(
319
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
320
                $e->getCode(),
321
                $e
322
            );
323
        }
324
    }
325
}
326