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
22:03
created

actionOverridesFromProject()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 46
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 34
nc 8
nop 2
dl 0
loc 46
ccs 0
cts 40
cp 0
crap 42
rs 8.7537
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(
123
            'Would you like to move the current override and make a new one and then diff this?',
124
            true
125
        )) {
126
            $output->writeln('<commment>Skipping ' . $relativePathToFileInOverrides . '</commment>');
127
128
            return false;
129
        }
130
131
        $symfonyStyle->section('Recreating Override');
132
        list($old, $new) = $this->fileOverrider->recreateOverride($relativePathToFileInOverrides);
133
        $this->renderKeyValue(
134
            [
135
                'Old Override' => $old,
136
                'New Override' => $new,
137
            ],
138
            $symfonyStyle
139
        );
140
        $projectRoot = $this->fileOverrider->getPathToProjectRoot();
141
        $output->writeln(<<<TEXT
142
        
143
Now we have created a new override from your freshly generated file, 
144
you need to manually copy across all the required changes from the old override into your project file.
145
146
Run this command <comment>in another terminal</comment>:
147
148
    cd $projectRoot
149
    
150
    meld .$new .$old && rm -f .$old
151
 
152
TEXT
153
        );
154
        $symfonyStyle->caution('You must do this bit really carefully and exactly as instructed!!');
155
156
        while (false === $symfonyStyle->confirm(
157
            'Confirm you have now copied all required changes from the old override to the new one?',
158
            false
159
        )
160
        ) {
161
            $symfonyStyle->warning('You must now copy all required changes from the old override to the new one');
162
        }
163
        $symfonyStyle->success("\n\nCompleted override update for $relativePathToFileInOverrides\n\n");
164
165
        return true;
166
    }
167
168
    private function renderKeyValue(array $keysToValues, SymfonyStyle $symfonyStyle): void
169
    {
170
        $symfonyStyle->newLine();
171
        $longestKey = max(array_map('strlen', array_keys($keysToValues)));
172
        foreach ($keysToValues as $key => $value) {
173
            $key = str_pad($key, $longestKey, ' ');
174
            $symfonyStyle->writeln("<comment>$key:</comment> $value");
175
        }
176
        $symfonyStyle->newLine();
177
    }
178
179
    private function renderTableOfUpdatedFiles(array $files, OutputInterface $output): void
180
    {
181
        list($updated, $same) = $files;
182
        if ([] !== $updated) {
183
            $output->writeln('Files Updated:');
184
            $table = new Table($output);
185
            foreach ($updated as $file) {
186
                $table->addRow([$file]);
187
            }
188
            $table->render();
189
        }
190
        if ([] !== $same) {
191
            $output->writeln('Files Same:');
192
            $table = new Table($output);
193
            foreach ($same as $file) {
194
                $table->addRow([$file]);
195
            }
196
            $table->render();
197
        }
198
    }
199
200
    private function actionOverridesFromProject(SymfonyStyle $symfonyStyle, OutputInterface $output): void
201
    {
202
        list($filesDifferent,) = $this->fileOverrider->compareOverridesWithProject();
203
        if ([] === $filesDifferent) {
204
            $symfonyStyle->success('All override files are up to date, nothing else required');
205
206
            return;
207
        }
208
        $symfonyStyle->note(<<<TEXT
209
210
Some override files are not up to date with project file changes.
211
    
212
What we need to do now is to update the override files with the changes you have made in your project files.
213
               
214
TEXT
215
        );
216
        $action = $symfonyStyle->choice(
217
            'How would you like to resolve this?',
218
            [
219
                'process'            => 'Process each file one at a time and decide to copy or not',
220
                'copyAllFromProject' => 'Update all override files with the content of the project files',
221
                'skipAll'            => 'Do not update any override files, lose all changes on project files (danger!)',
222
            ],
223
            'Process each file one at a time and decide to copy or not'
224
        );
225
        switch ($action) {
226
            case 'copyAllFromProject':
227
                $toUpdate = $filesDifferent;
228
                break;
229
            case 'skipAll':
230
                $toUpdate = [];
231
                break;
232
            case 'process':
233
                $toUpdate = $this->processFilesChanges($filesDifferent, $symfonyStyle, $output);
234
                break;
235
            default:
236
                throw new \RuntimeException('Invalid action ' . $action);
237
        }
238
239
        if ([] === $toUpdate) {
240
            $symfonyStyle->success('No updates to apply');
241
242
            return;
243
        }
244
        $this->renderTableOfUpdatedFiles($this->fileOverrider->updateOverrideFiles($toUpdate), $output);
245
        $output->writeln('<info>Overrides have been updated from the project</info>');
246
    }
247
248
    private function processFilesChanges(
249
        array $filesDifferent,
250
        SymfonyStyle $symfonyStyle,
251
        OutputInterface $output
252
    ): array {
253
        $toUpdate = [];
254
        foreach ($filesDifferent as $relativePathToFileInProject => $details) {
255
            $symfonyStyle->section('Processing ' . $relativePathToFileInProject);
256
//            $table = new Table($output);
257
//            $table->setHeaders(['Key', 'Value']);
258
//            $table->addRows(
259
//                [
260
//                    ['Project File', $relativePathToFileInProject],
261
//                    ['Override File', $details['overridePath']],
262
//                    ['Diff Size', substr_count($details['diff'], "\n")],
263
//                ]
264
//            );
265
//            $table->render();
266
            $this->renderKeyValue(
267
                [
268
                    'Project File'  => $relativePathToFileInProject,
269
                    'Override File' => $details['overridePath'],
270
                    'Diff Size'     => substr_count($details['diff'], "\n"),
271
                ],
272
                $symfonyStyle
273
            );
274
            $output->writeln('<info>Diff:</info>');
275
            $output->write($details['diff']);
276
            $output->writeln("\n\n");
277
            if (true === $symfonyStyle->ask(
278
                'Would you like to copy the project file contents into the override file?',
279
                true
280
            )
281
            ) {
282
                $symfonyStyle->success(
283
                    'adding ' . $relativePathToFileInProject .
284
                    ' to list of files that will be copied into the overrides'
285
                );
286
                $toUpdate[$relativePathToFileInProject] = true;
287
                continue;
288
            }
289
            $symfonyStyle->note(
290
                'skipping ' . $relativePathToFileInProject
291
                . ' from list of files that will be copied into the overrides'
292
            );
293
        }
294
295
        return $toUpdate;
296
    }
297
298
    /**
299
     * @throws DoctrineStaticMetaException
300
     */
301
    protected function configure(): void
302
    {
303
        try {
304
            $this
305
                ->setName(AbstractCommand::COMMAND_PREFIX . 'overrides:update')
306
                ->setDefinition(
307
                    [
308
                        new InputOption(
309
                            self::OPT_OVERRIDE_ACTION,
310
                            self::OPT_OVERRIDE_ACTION_SHORT,
311
                            InputOption::VALUE_REQUIRED,
312
                            'One of [ fromProject,  toProject ]'
313
                        ),
314
                        $this->getProjectRootPathOption(),
315
                    ]
316
                )->setDescription(
317
                    'Update project overrides'
318
                );
319
        } catch (\Exception $e) {
320
            throw new DoctrineStaticMetaException(
321
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
322
                $e->getCode(),
323
                $e
324
            );
325
        }
326
    }
327
}
328