Completed
Push — master ( 115aec...11e20f )
by Jack
02:31
created

UpdateModules::processOneModule()   F

Complexity

Conditions 20
Paths 480

Size

Total Lines 114
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 114
rs 3.1717
c 0
b 0
f 0
cc 20
eloc 52
nc 480
nop 5

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 46 and the first side effect is on line 8.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
/**
4
 * main class running all the updates
5
 *
6
 *
7
 */
8
class UpdateModules extends BuildTask
0 ignored issues
show
Bug introduced by
Possible parse error: class missing opening or closing brace
Loading history...
9
{
10
    protected $enabled = true;
11
12
    protected $title = "Update Modules";
13
14
    protected $description = "Adds files necessary for publishing a module to GitHub. The list of modules is specified in standard config or else it retrieves a list of modules from GitHub.";
15
16
    /**
17
     * e.g.
18
     * - moduleA
19
     * - moduleB
20
     * - moduleC
21
     *
22
     *
23
     * @var array
24
     */
25
    private static $modules_to_update = array();
26
27
    /**
28
     * e.g.
29
     * - ClassNameForUpdatingFileA
30
     * - ClassNameForUpdatingFileB
31
     *
32
     * @var array
33
     */
34
    private static $files_to_update = array();
35
    /**
36
     * e.g.
37
     * - ClassNameForUpdatingFileA
38
     * - ClassNameForUpdatingFileB
39
     *
40
     * @var array
41
     */
42
    private static $commands_to_run = array();
43
    
44
    public static $unsolvedItems = array();
45
46
    public function run($request) {
47
        increase_time_limit_to(3600);
48
49
        //Check temp module folder is empty
50
        $tempFolder = GitHubModule::Config()->get('absolute_temp_folder');
51
        $tempDirFiles = scandir($tempFolder);
52
        if (count($tempDirFiles) > 2) {
53
            die ( '<h2>' . $tempFolder . ' is not empty, please delete or move files </h2>');
54
        }
55
56
        //Get list of all modules from GitHub
57
        $gitUserName = $this->Config()->get('git_user_name');
58
		
59
		$modules = GitHubModule::getRepoList();
60
		
61
62
63
        $updateComposerJson = $this->Config()->get('update_composer_json');
64
        
65
66
		
67
        $limitedModules = $this->Config()->get('modules_to_update');
68
69
        if($limitedModules && count($limitedModules)) {
70
            $modules = array_intersect($modules, $limitedModules);
71
        }
72
73
74
75
        /*
76
         * Get files to add to modules
77
         * */
78
        $files = ClassInfo::subclassesFor('AddFileToModule');
79
80
        array_shift($files);
81
        $limitedFileClasses = $this->Config()->get('files_to_update');
82
        if($limitedFileClasses && count($limitedFileClasses)) {
83
            $files = array_intersect($files, $limitedFileClasses);
84
        }
85
86
        /*
87
         * Get commands to run on modules
88
         * */
89
90
        $commands = ClassInfo::subclassesFor('RunCommandLineMethodOnModule');
91
92
93
        array_shift($commands);
94
        $limitedCommands = $this->Config()->get('commands_to_run');
95
        if($limitedCommands && count($limitedCommands)) {
96
            $commands = array_intersect($commands, $limitedCommands);
97
        }
98
99
100
		set_error_handler ('errorHandler', E_ALL);
101
        foreach($modules as $count => $module) {
102
			$this->currentModule = $module;
103
			try {
104
				
105
				$this->processOneModule($module, $count, $files, $commands, $updateComposerJson);
106
			}
107
			catch (Exception $e) {
108
				GeneralMethods::outputToScreen ("<li> Could not complete processing $module: " .  $e->getMessage() . " </li>");
109
			}
110
			
111
112
        }
113
 
114
		restore_error_handler();
115
        
116
        $this->writeLog();
117
        //to do ..
118
    }
119
    
120
    protected function errorHandler(int $errno , string $errstr) {
121
122
		GeneralMethods::outputToScreen ("<li> Could not complete processing module: " .  $errstr . " </li>");
123
  
124
        UpdateModules::addUnsolvedProblem($this->currentModule, "Could not complete processing module: " . $errstr);
125
              
126
		return true;
127
	}
128
    
129
    protected function processOneModule($module, $count, $files, $commands, $updateComposerJson) {
130
		    
131
		    if ( stripos($module, 'silverstripe-')  === false ) {
132
                $module = "silverstripe-" . $module;
133
            }
134
            echo "<h2>" . ($count+1) . ". ".$module."</h2>";
135
136
137
            $moduleObject = GitHubModule::get_or_create_github_module($module);
138
139
            $this->checkUpdateTag($moduleObject);
140
141
            // Check if all necessary files are perfect on GitHub repo already,
142
            // if so we can skip that module. But! ... if there are commands to run
143
            // over the files in the repo, then we need to clone the repo anyhow,
144
            // so skip the check
145
            if (count($commands) == 0 && ! $updateComposerJson) {
146
                $moduleFilesOK = true;
147
148
                foreach($files as $file) {
149
                    $fileObj = $file::create($moduleObject);
150
                    $checkFileName = $fileObj->getFileLocation();
151
                    $GitHubFileText = $moduleObject -> getRawFileFromGithub($checkFileName);
152
                    if ($GitHubFileText) {
153
                        $fileCheck = $fileObj->compareWithText($GitHubFileText);
154
                        if ( ! $fileCheck) {
155
                            $moduleFilesOK = false;
156
                        }
157
                    }
158
                    else {
159
                        $moduleFilesOK = false;
160
                    }
161
                }
162
                
163
                
164
165
                if ($moduleFilesOK) {
166
                    GeneralMethods::outputToScreen ("<li> All files in $module OK, skipping to next module ... </li>");
167
                    continue;
168
                }
169
            }
170
171
            $repository = $moduleObject->checkOrSetGitCommsWrapper($forceNew = true);
172
173
174
			$this->moveOldReadMe($moduleObject);
175
176
            $this->checkConfigYML($moduleObject);
177
178
179
            if ($updateComposerJson) {
180
                $composerJsonObj = new ComposerJson ($moduleObject);
181
                $composerJsonObj->updateJsonData();
182
                $moduleObject->setDescription($composerJsonObj->getDescription());
183
            }
184
185
			$excludedWords = $this->Config()->get('excluded_words');
186
			
187
			
188
			if (count($excludedWords) > 0) 
189
			{
190
				$folder = GitHubModule::Config()->get('absolute_temp_folder') . '/' . $moduleObject->moduleName . '/';
191
192
				$results = $this->checkDirExcludedWords($folder.'/'.$moduleObject->modulename, $excludedWords);
193
				
194
				
195
				if ($results && count ($results > 0)) 
196
				{
197
					$msg = "<h4>The following excluded words were found: </h4><ul>";
198
					foreach ($results as $file => $words) {
199
						foreach ($words as $word) {
200
							$msg .= "<li>$word in $file</li>";
201
						}
202
					}
203
					$msg .= '</ul>';
204
					
205
					//trigger_error ("excluded words found in files(s)");
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
206
					GeneralMethods::outputToScreen ($msg);
207
					UpdateModules::$unsolvedItems[$moduleObject->ModuleName] = $msg;
208
				}
209
				
210
			}
211
212
213
            foreach($files as $file) {
214
                //run file update
215
216
                $obj = $file::create($moduleObject);
217
                $obj->run();
218
            }
219
220
			$moduleDir = $moduleObject->Directory();
221
222
            foreach($commands as $command) {
223
                //run file update
224
                
225
                
226
                $obj = $command::create($moduleDir);
227
                $obj->run();
228
                
229
                
230
                //run command
231
            }
232
233
            //Update Repository description
234
            //$moduleObject->updateGitHubInfo(array());
0 ignored issues
show
Unused Code Comprehensibility introduced by
89% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
235
236
            if( ! $moduleObject->add()) {
237
			
238
				$msg = "Could not add files module to Repo";
239
				GeneralMethods::outputToScreen ($msg);
240
				UpdateModules::$unsolvedItems[$moduleObject->ModuleName] = $msg;
241
				continue;
242
			
243
			}
244
            if( ! $moduleObject->commit()) 	{
245
				$msg = "Could not commit files to Repo";
246
				GeneralMethods::outputToScreen ($msg);
247
				UpdateModules::$unsolvedItems[$moduleObject->ModuleName] = $msg;
248
				continue;				
249
			}
250
			
251
            if( ! $moduleObject->push()) {
252
				$msg = "Could not push files to Repo";
253
				GeneralMethods::outputToScreen ($msg);
254
				UpdateModules::$unsolvedItems[$moduleObject->ModuleName] = $msg;
255
				continue;					
256
			}
257
            if( ! $moduleObject->removeClone()) {
258
			{
259
				$msg = "Could not remove local copy of repo";
260
				GeneralMethods::outputToScreen ($msg);
261
				UpdateModules::$unsolvedItems[$moduleObject->ModuleName] = $msg;				
262
			}
263
			
264
			$moduleObject->addRepoToScrutinzer();
265
            
266
	}
267
    
268
269
    
270
    protected function renameTest($moduleObject) {
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_PROTECTED
Loading history...
271
		
272
		$oldName = $moduleObject->Directory() . "/tests/ModuleTest.php";
273
		
274
		if ( ! file_exists($oldName) ) 
275
		{
276
			print_r ($oldName);
277
			return false;
278
		}
279
		
280
		
281
		
282
		$newName = $moduleObject->Directory() . "tests/" . $moduleObject->ModuleName . "Test.php";
283
		
284
		GeneralMethods::outputToScreen ("Renaming $oldName to $newName");
285
		
286
		unlink ($newName);
287
		
288
		rename($oldName, $newName);
289
290
		
291
	}
292
293
	public static function addUnsolvedProblem($moduleName, $problemString) {
294
		if (!isset (UpdateModules::$unsolvedItems[$moduleName]) )
295
		{
296
			UpdateModules::$unsolvedItems[$moduleName] = array();
297
		}
298
		array_push (UpdateModules::$unsolvedItems[$moduleName], $problemString);
299
	}
300
		
301
	protected function writeLog() {
302
		
303
		
304
305
		$mailTo = $this->Config()->get('report_email');
306
		$debug = $this->Config()->get('debug');
307
		
308
		$dateStr =  date("Y/m/d H:i:s");
309
		
310
		$html = '<h1> Modules checker report at ' .$dateStr . '</h1>';
311
		
312
		if (count (UpdateModules::$unsolvedItems) == 0) {
313
			$html .= ' <h2> No unresolved problems in modules</h2>';
314
		}
315
		
316
		else {
317
			$html .= '
318
				<h2> Unresolved problems in modules</h2>
319
			
320
			<table border = 1>
321
					<tr><th>Module</th><th>Problem</th></tr>';
322
		
323
			foreach (UpdateModules::$unsolvedItems as $moduleName => $problems) {
324
325
				foreach ($problems as $problem) {
326
				
327
					$html .= '<tr><td>'.$moduleName.'</td><td>'. $problem .'</td></tr>';
328
				}
329
			}
330
			$html .= '</table>';
331
;			
332
			
333
		}
334
		
335
		
336
		$logFolder = getcwd() . '/../modulechecks/logs/';
337
		
338
		$filename = $logFolder . date('U') . '.html';
339
		
340
		GeneralMethods::outputToScreen ("Writing to $filename");
341
		
342
		$result = file_put_contents ( $filename, $html);
343
		
344
		if ( ! $result )
345
		{
346
			GeneralMethods::outputToScreen ("Could not write log file");
347
		}
348
		
349
350
	
351
	}
352
353
    protected function checkConfigYML($module)
354
    {
355
        $configYml = ConfigYML::create($module)->reWrite();
356
 
357
    }
358
359
    private function checkFile($module, $filename) {
360
        $folder = GitHubModule::Config()->get('absolute_temp_folder');
361
        return file_exists($folder.'/'.$module.'/'.$filename);
362
    }
363
364
    private function checkReadMe($module) {
365
        return $this->checkFile($module, "README.MD");
366
    }
367
368
    private function checkDirExcludedWords($directory, $wordArray) {
369
        $filesAndFolders = scandir ($directory);
370
371
        $problem_files = array();
372
        foreach ($filesAndFolders as $fileOrFolder) {
373
374
            if ($fileOrFolder == '.' || $fileOrFolder == '..' || $fileOrFolder == '.git'  ) {
375
                continue;
376
            }
377
378
            $fileOrFolderFullPath = $directory . '/' . $fileOrFolder;
379
            if (is_dir($fileOrFolderFullPath)) {
380
                $dir = $fileOrFolderFullPath;
381
                $problem_files = array_merge ($this->checkDirExcludedWords ($dir, $wordArray) , $problem_files);
382
            }
383
            if (is_file($fileOrFolderFullPath)) {
384
                $file = $fileOrFolderFullPath;
385
                $matchedWords = $this->checkFileExcludedWords($file, $wordArray);
386
387
                if ($matchedWords) {
388
		
389
                   $problem_files[$file] = $matchedWords;
390
                }
391
            }
392
        }
393
394
        return $problem_files;
395
    }
396
397
    private function checkFileExcludedWords($fileName, $wordArray) {
398
		
399
400
        $matchedWords = array();
401
402
		$fileName = str_replace ('////', '/',  $fileName);
403
		if (filesize ($fileName) == 0 ) return $matchedWords; 
404
405
406
        $fileContent = file_get_contents($fileName);
407
		if (!$fileContent) {
408
			
409
			$msg = "Could not open $fileName to check for excluded words";
410
			
411
			GeneralMethods::outputToScreen ($msg);
412
			UpdateModules::$unsolvedItems[$moduleObject->ModuleName] = $msg;
413
		}
414
415
        foreach ($wordArray as $word)  {
416
			
417
418
            $matches = array();
419
            $matchCount = preg_match_all('/' . $word . '/i', $fileContent);
420
            
421
            
422
           
423
            
424
            
425
            if ($matchCount > 0) {
426
                array_push ($matchedWords, $word);
427
428
            }
429
        }
430
431
        return $matchedWords;
432
433
    }
434
435
    private function checkUpdateTag($moduleObject) {
436
437
        $aWeekAgo = strtotime("-1 weeks");
438
        $tag = $moduleObject->getLatestTag();
439
440
        $commitTime = $moduleObject->getLatestCommitTime();
441
442
		if (! $commitTime) // if no commits, cannot create a tag
443
		{
444
			return false;
445
		}
446
447
        $createTag = false;
448
449
        if ( ! $tag ) {
450
            $createTag = true;
451
            $newTagString = '1.0.0';
452
        }
453
454
455
456
        else if ($tag && $commitTime > $tag['timestamp'] && $commitTime < $aWeekAgo) {
457
            $createTag = true;
458
            $tag['tagparts'][1] = $tag['tagparts'][1] + 1;
459
            $newTagString = trim(implode ('.', $tag['tagparts']));
460
        }
461
462
        if ($createTag) {
463
464
            GeneralMethods::outputToScreen ('<li> Creating new tag  '.$newTagString.' ... </li>');
465
466
            //git tag -a 0.0.1 -m "testing tag"
467
            $options = array (
468
                'a' => $newTagString,
469
                'm' => $this->Config()->get('tag_create_message')
470
            );
471
472
            $moduleObject->createTag ($options);
473
474
        }
475
476
		return true;
477
478
    }
479
    
480
    protected function moveOldReadMe($moduleObject) {
481
		$tempDir = GitHubModule::Config()->get('absolute_temp_folder');
482
		$oldReadMe = $tempDir . '/' .  $moduleObject->ModuleName . '/' .'README.md';
483
		
484
		if (!file_exists($oldReadMe))
485
		{
486
			return false;
487
		}
488
		
489
490
		$oldreadmeDestinationFiles = array (
491
				'docs/en/INDEX.md',
492
				'docs/en/README.old.md', 
493
			);
494
495
496
		$copied = false;
497
		foreach ($oldreadmeDestinationFiles as $file) {
498
			$filePath = $tempDir . '/' .  $moduleObject->ModuleName . '/' . $file;
499
			
500
			if (!file_exists($filePath)) {
501
				$copied = true;
502
				copy($oldReadMe, $filePath);
503
			}
504
			
505
		}
506
		if ($copied) 
507
		{
508
			unlink ($oldReadMe);
509
		}
510
	}
511
512
513
}
514