1
|
|
|
<?php |
|
|
|
|
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* does everything with one module |
5
|
|
|
* |
6
|
|
|
* see https://github.com/cpliakas/git-commsWrapper for info on the git commsWrapper module |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
|
10
|
|
|
use GitWrapper\GitWrapper; |
11
|
|
|
|
12
|
|
|
require_once '../vendor/autoload.php'; |
13
|
|
|
|
14
|
|
|
class GitHubModule extends DataObject |
|
|
|
|
15
|
|
|
{ |
16
|
|
|
|
17
|
|
|
|
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* e.g. |
21
|
|
|
* @var string |
22
|
|
|
*/ |
23
|
|
|
private static $github_account_base_url = ''; |
|
|
|
|
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* e.g. boss |
27
|
|
|
* @var string |
28
|
|
|
*/ |
29
|
|
|
private static $github_user_name = ''; |
|
|
|
|
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* |
33
|
|
|
* |
34
|
|
|
* @var GitcommsWrapper |
35
|
|
|
*/ |
36
|
|
|
private static $github_user_email = ''; |
|
|
|
|
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* where the git module is temporary |
40
|
|
|
* cloned and fixed up |
41
|
|
|
* should be an absolute_path |
42
|
|
|
* |
43
|
|
|
* @var string |
44
|
|
|
*/ |
45
|
|
|
private static $path_to_private_key = ''; |
|
|
|
|
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* where the git module is temporary |
49
|
|
|
* cloned and fixed up |
50
|
|
|
* should be an absolute_path |
51
|
|
|
* |
52
|
|
|
* @var string |
53
|
|
|
*/ |
54
|
|
|
private static $absolute_temp_folder = ''; |
|
|
|
|
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* wrapper also relates to one git hub repo only!!!! |
58
|
|
|
* |
59
|
|
|
* @var GitcommsWrapper |
60
|
|
|
*/ |
61
|
|
|
protected $commsWrapper = null; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* |
65
|
|
|
* |
66
|
|
|
* @var git module |
67
|
|
|
*/ |
68
|
|
|
protected $gitRepo = null; |
69
|
|
|
|
70
|
|
|
private static $db = array( |
|
|
|
|
71
|
|
|
'ModuleName' => 'VarChar(100)', |
72
|
|
|
'Description' => 'VarChar(300)' |
73
|
|
|
); |
74
|
|
|
|
75
|
|
|
|
76
|
|
|
private static $indexes = array( |
|
|
|
|
77
|
|
|
'ModuleName' => true, |
78
|
|
|
); |
79
|
|
|
|
80
|
|
|
|
81
|
|
|
private static $casting = array( |
|
|
|
|
82
|
|
|
'Directory' => 'Varchar(255)', |
83
|
|
|
'URL' => 'Varchar(255)', |
84
|
|
|
); |
85
|
|
|
|
86
|
|
|
public function getDirectory() |
87
|
|
|
{ |
88
|
|
|
return $this->Directory(); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
public function getDescription() |
|
|
|
|
92
|
|
|
{ |
93
|
|
|
return $this->Description(); |
|
|
|
|
94
|
|
|
} |
95
|
|
|
/** |
96
|
|
|
* absolute path |
97
|
|
|
* @return string | null |
|
|
|
|
98
|
|
|
*/ |
99
|
|
|
public function Directory() |
100
|
|
|
{ |
101
|
|
|
$tempFolder = $this->Config()->get('absolute_temp_folder'); |
102
|
|
|
if ($this->ModuleName) { |
|
|
|
|
103
|
|
|
$folder = $tempFolder.'/'.$this->ModuleName; |
|
|
|
|
104
|
|
|
if (file_exists($folder)) { |
105
|
|
|
if (file_exists($folder)) { |
106
|
|
|
return $folder; |
107
|
|
|
} |
108
|
|
|
} else { |
109
|
|
|
mkdir($folder); |
110
|
|
|
if (file_exists($folder)) { |
111
|
|
|
return $folder; |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
public function getURL() |
118
|
|
|
{ |
119
|
|
|
return $this->URL(); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
|
123
|
|
|
public function LongModuleName() |
124
|
|
|
{ |
125
|
|
|
return $this->Config()->get('github_user_name').'/'.$this->ModuleName; |
|
|
|
|
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
|
129
|
|
|
public function MediumModuleName() |
|
|
|
|
130
|
|
|
{ |
131
|
|
|
return $this->ModuleName; |
|
|
|
|
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @todo: check that silverstripe- is at the start of string. |
136
|
|
|
* @return string |
137
|
|
|
*/ |
138
|
|
|
public function ShortModuleName() |
139
|
|
|
{ |
140
|
|
|
return str_replace('silverstripe-', '', $this->ModuleName); |
|
|
|
|
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
public function ShortUCFirstName() |
144
|
|
|
{ |
145
|
|
|
$array = explode('_', $this->ShortModuleName()); |
146
|
|
|
|
147
|
|
|
$name = ''; |
148
|
|
|
|
149
|
|
|
foreach ($array as $part) { |
150
|
|
|
$name .= ucfirst($part); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
return $name; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
|
157
|
|
|
public function ModuleNameFirstLetterCapital() |
158
|
|
|
{ |
159
|
|
|
$shortName = $this->ShortModuleName(); |
160
|
|
|
|
161
|
|
|
$firstLetterCapitalName = str_replace('_', ' ', $shortName); |
162
|
|
|
$firstLetterCapitalName = str_replace('-', ' ', $firstLetterCapitalName); |
163
|
|
|
|
164
|
|
|
|
165
|
|
|
return strtolower($firstLetterCapitalName); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
public function setDescription($str) |
169
|
|
|
{ |
170
|
|
|
$this->Description = trim($str); |
|
|
|
|
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* check if URL exists and returns it |
175
|
|
|
* @var string | null |
176
|
|
|
*/ |
177
|
|
|
public function URL() |
178
|
|
|
{ |
179
|
|
|
$username = $this->Config()->get('github_user_name'); |
180
|
|
|
return 'https://github.com/'.$username.'/'.$this->ModuleName; |
|
|
|
|
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
protected function IsDirGitRepo($directory) |
184
|
|
|
{ |
185
|
|
|
return file_exists($directory."/.git"); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* |
191
|
|
|
* @param bool (optional) $forceNew - create a new repo and ditch all changes |
192
|
|
|
* @return Git Repo Object |
193
|
|
|
*/ |
194
|
|
|
public function checkOrSetGitCommsWrapper($forceNew = false) |
195
|
|
|
{ |
196
|
|
|
//check if one has been created already... |
197
|
|
|
if (! $this->gitRepo) { |
198
|
|
|
|
199
|
|
|
//basic check |
200
|
|
|
if ($this->ModuleName == '') { |
|
|
|
|
201
|
|
|
user_error('ModuleName element must be set before using git repository commands'); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
//create comms |
205
|
|
|
$this->commsWrapper = new GitWrapper(); |
|
|
|
|
206
|
|
|
|
207
|
|
|
// Stream output of subsequent Git commands in real time to STDOUT and STDERR. |
208
|
|
|
if (Director::is_cli()) { |
209
|
|
|
$this->commsWrapper->streamOutput(); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
|
213
|
|
|
if (! $this->Config()->get('path_to_private_key')) { |
214
|
|
|
user_error("We recommend you set private key"); |
215
|
|
|
} |
216
|
|
|
// Optionally specify a private key other than one of the defaults. |
217
|
|
|
$this->commsWrapper->setPrivateKey($this->Config()->get('path_to_private_key')); |
218
|
|
|
|
219
|
|
|
//if directory exists, return existing repo, |
220
|
|
|
//otherwise clone it.... |
221
|
|
|
if ($this->IsDirGitRepo($this->Directory())) { |
222
|
|
|
if ($forceNew) { |
223
|
|
|
$this->removeClone(); |
224
|
|
|
return $this->checkOrSetGitCommsWrapper(false); |
225
|
|
|
} |
226
|
|
|
$this->gitRepo = $this->commsWrapper->workingCopy($this->Directory()); |
227
|
|
|
} else { |
228
|
|
|
GeneralMethods::output_to_screen("cloning ... ".$this->fullGitURL(), 'created'); |
229
|
|
|
|
230
|
|
|
$this->gitRepo = null; |
231
|
|
|
$cloneAttempts = 0; |
232
|
|
|
while (! $this->gitRepo) { |
233
|
|
|
$cloneAttempts ++; |
234
|
|
|
if ($cloneAttempts == 4) { |
235
|
|
|
user_error('Failed to clone module ' . $this->LongModuleName() . ' after ' . ($cloneAttempts - 1). ' attemps.', E_USER_ERROR); |
236
|
|
|
//UpdateModules::$unsolvedItems[$this->ModuleName()] = 'Failed to clone modules'; |
|
|
|
|
237
|
|
|
UpdateModules::addUnsolvedProblem($this->ModuleName(), 'Failed to clone modules'); |
|
|
|
|
238
|
|
|
} |
239
|
|
|
try { |
240
|
|
|
$this->commsWrapper->setTimeout(240); //Big modules need a longer timeout |
241
|
|
|
$this->gitRepo = $this->commsWrapper->cloneRepository( |
242
|
|
|
$this->fullGitURL(), |
243
|
|
|
$this->Directory() |
244
|
|
|
); |
245
|
|
|
$this->commsWrapper->setTimeout(60); |
246
|
|
|
} catch (Exception $e) { |
247
|
|
|
if (strpos($e->getMessage(), 'already exists and is not an empty directory') !== false) { |
248
|
|
|
user_error($e->getMessage(), E_USER_ERROR); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
GeneralMethods::outputToScreen('<li>Failed to clone repository: ' . $e->getMessage() . '</li>'); |
252
|
|
|
GeneralMethods::outputToScreen('<li>Waiting 8 seconds to try again ...: </li>'); |
253
|
|
|
$this->removeClone(); |
254
|
|
|
sleep(8); |
255
|
|
|
} |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
$this->gitRepo->config("push.default", "simple"); |
259
|
|
|
$this->gitRepo->config("user.name", $this->Config()->get('github_user_name')); |
260
|
|
|
$this->gitRepo->config("user.email", $this->Config()->get('github_user_email')); |
261
|
|
|
$this->commsWrapper->git('config -l'); |
262
|
|
|
} |
263
|
|
|
return $this->gitRepo; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* @var string |
268
|
|
|
*/ |
269
|
|
|
public function fullGitURL() |
270
|
|
|
{ |
271
|
|
|
$username = $this->Config()->get('github_user_name'); |
272
|
|
|
$gitURL = $this->Config()->get('github_account_base_url'); |
|
|
|
|
273
|
|
|
return '[email protected]:/'.$username.'/'.$this->ModuleName.'.git'; |
|
|
|
|
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* pulls a git repo |
278
|
|
|
* |
279
|
|
|
* @return bool | this |
|
|
|
|
280
|
|
|
*/ |
281
|
|
|
public function pull() |
282
|
|
|
{ |
283
|
|
|
$git = $this->checkOrSetGitCommsWrapper(); |
284
|
|
|
if ($git) { |
285
|
|
|
try { |
286
|
|
|
$git->pull(); |
287
|
|
|
} catch (GitWrapper\GitException $e) { |
|
|
|
|
288
|
|
|
print_r($e); |
289
|
|
|
throw $e; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
|
293
|
|
|
//GeneralMethods::output_to_screen($git->getOutput()); |
|
|
|
|
294
|
|
|
return $this; |
295
|
|
|
} |
296
|
|
|
return false; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
/** |
300
|
|
|
* commits a git repo |
301
|
|
|
* |
302
|
|
|
* @param string $message |
303
|
|
|
* |
304
|
|
|
* @return bool | this |
|
|
|
|
305
|
|
|
*/ |
306
|
|
|
public function commit($message = 'PATCH: module clean-up') |
307
|
|
|
{ |
308
|
|
|
$git = $this->checkOrSetGitCommsWrapper(); |
309
|
|
|
if ($git) { |
310
|
|
|
try { |
311
|
|
|
$git->commit($message); |
312
|
|
|
} catch (Exception $e) { |
313
|
|
|
$errStr = $e->getMessage(); |
314
|
|
|
if (stripos($errStr, 'nothing to commit') === false) { |
315
|
|
|
print_r($e); |
316
|
|
|
throw $e; |
317
|
|
|
} else { |
318
|
|
|
GeneralMethods::output_to_screen('No changes to commit'); |
319
|
|
|
} |
320
|
|
|
} |
321
|
|
|
//GeneralMethods::output_to_screen($git->getOutput()); |
|
|
|
|
322
|
|
|
|
323
|
|
|
return $this; |
324
|
|
|
} |
325
|
|
|
return false; |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
/** |
329
|
|
|
* adds all files to a git repo |
330
|
|
|
* @return bool | this |
|
|
|
|
331
|
|
|
*/ |
332
|
|
|
public function add() |
333
|
|
|
{ |
334
|
|
|
GeneralMethods::output_to_screen('Adding new files to '.$this->ModuleName.' ... ', "created"); |
|
|
|
|
335
|
|
|
|
336
|
|
|
$git = $this->checkOrSetGitcommsWrapper(); |
337
|
|
|
if ($git) { |
338
|
|
|
try { |
339
|
|
|
$git->add("."); |
340
|
|
|
} catch (GitWrapper\GitException $e) { |
|
|
|
|
341
|
|
|
$errStr = $e->getMessage(); |
342
|
|
|
if (stripos($errStr, 'did not match any files') === false) { |
343
|
|
|
print_r($e); |
344
|
|
|
throw $e; |
345
|
|
|
} else { |
346
|
|
|
GeneralMethods::output_to_screen('No new files to add to $module. '); |
347
|
|
|
} |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
//GeneralMethods::output_to_screen($git->getOutput()); |
|
|
|
|
351
|
|
|
|
352
|
|
|
return $this; |
353
|
|
|
} |
354
|
|
|
return false; |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
/** |
358
|
|
|
* adds all files to a git repo |
359
|
|
|
* |
360
|
|
|
* @return bool | this |
|
|
|
|
361
|
|
|
*/ |
362
|
|
|
public function push() |
363
|
|
|
{ |
364
|
|
|
GeneralMethods::output_to_screen('Pushing files to '.$this->ModuleName.' ... ', "created"); |
|
|
|
|
365
|
|
|
|
366
|
|
|
$git = $this->checkOrSetGitcommsWrapper(); |
367
|
|
|
if ($git) { |
368
|
|
|
$pushed = false; |
369
|
|
|
$pushAttempts = 0; |
370
|
|
|
while (! $pushed) { |
371
|
|
|
$pushAttempts ++; |
372
|
|
|
try { |
373
|
|
|
$git->push(); |
374
|
|
|
$pushed = true; |
375
|
|
|
} catch (Exception $e) { |
376
|
|
|
if ($pushAttempts == 3) { |
377
|
|
|
$git->getOutput(); |
378
|
|
|
print_r($e); |
379
|
|
|
throw $e; |
380
|
|
|
} else { |
381
|
|
|
GeneralMethods::outputToScreen('<li>Failed to push repository: ' . $e->getMessage() . '</li>'); |
382
|
|
|
GeneralMethods::outputToScreen('<li>Waiting 8 seconds to try again ...: </li>'); |
383
|
|
|
sleep(8); |
384
|
|
|
} |
385
|
|
|
} |
386
|
|
|
} |
387
|
|
|
return $this; |
388
|
|
|
} |
389
|
|
|
return false; |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
/** |
393
|
|
|
* removes a cloned repo |
394
|
|
|
* |
395
|
|
|
* |
396
|
|
|
*/ |
397
|
|
|
public function removeClone() |
398
|
|
|
{ |
399
|
|
|
$dir = $this->Directory(); |
400
|
|
|
GeneralMethods::output_to_screen('Removing '.$dir.' and all its contents ... ', "created"); |
401
|
|
|
$this->gitRepo = null; |
402
|
|
|
FileSystem::removeFolder($dir); // removes contents but not the actual folder |
403
|
|
|
//rmdir ($dir); |
|
|
|
|
404
|
|
|
return ! file_exists($dir); |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* retrieves a raw file from Github |
409
|
|
|
* |
410
|
|
|
* @return string | bool |
411
|
|
|
*/ |
|
|
|
|
412
|
|
|
|
413
|
|
|
public function getRawFileFromGithub($fileName) |
414
|
|
|
{ |
415
|
|
|
$gitUserName = $this->Config()->get('github_user_name'); |
416
|
|
|
$branch = 'master'; |
417
|
|
|
|
418
|
|
|
$rawURL = 'https://raw.githubusercontent.com/' . $gitUserName . '/' . $this->ModuleName . '/' . $branch . '/' . $fileName; |
|
|
|
|
419
|
|
|
|
420
|
|
|
set_error_handler(array($this, 'catchFopenWarning'), E_WARNING); |
421
|
|
|
$file = fopen($rawURL, 'r'); |
422
|
|
|
restore_error_handler(); |
423
|
|
|
|
424
|
|
|
if (! $file) { |
425
|
|
|
GeneralMethods::outputToScreen('<li>Could not find ' . $rawURL . '</li>'); |
426
|
|
|
return false; |
427
|
|
|
} |
428
|
|
|
$content = ''; |
429
|
|
|
while (! feof($file)) { |
430
|
|
|
$content .= fgets($file); |
431
|
|
|
} |
432
|
|
|
fclose($file); |
433
|
|
|
return $content; |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
/* |
437
|
|
|
* This function is just used to suppression of warnings |
438
|
|
|
* */ |
439
|
|
|
private function catchFopenWarning($errno, $errstr) |
|
|
|
|
440
|
|
|
{ |
441
|
|
|
// |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
|
445
|
|
|
public static function get_or_create_github_module($moduleName) |
|
|
|
|
446
|
|
|
{ |
447
|
|
|
$moduleName = trim($moduleName); |
448
|
|
|
$filter = array('ModuleName' => $moduleName); |
449
|
|
|
$gitHubModule = GitHubModule::get()->filter($filter)->first(); |
450
|
|
|
if (! $gitHubModule) { |
451
|
|
|
$gitHubModule = GitHubModule::create($filter); |
452
|
|
|
$gitHubModule->write(); |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
return $gitHubModule; |
456
|
|
|
} |
457
|
|
|
|
458
|
|
|
|
459
|
|
|
public function getLatestCommitTime() |
460
|
|
|
{ |
461
|
|
|
// equivalent to git log -1 --format=%cd . |
462
|
|
|
|
463
|
|
|
$git = $this->checkOrSetGitCommsWrapper(); |
464
|
|
|
if ($git) { |
465
|
|
|
$options = array( |
466
|
|
|
'format' => "%cd", |
467
|
|
|
'1' => true |
468
|
|
|
); |
469
|
|
|
|
470
|
|
|
try { |
471
|
|
|
$result = $git->log($options); |
472
|
|
|
} catch (Exception $e) { |
473
|
|
|
$errStr = $e->getMessage(); |
474
|
|
|
if (stripos($errStr, 'does not have any commits') === false) { |
475
|
|
|
print_r($e); |
476
|
|
|
throw $e; |
477
|
|
|
} else { |
478
|
|
|
return false; |
479
|
|
|
} |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
if ($result) { |
483
|
|
|
return (strtotime($result)); |
484
|
|
|
} else { |
485
|
|
|
return false; |
486
|
|
|
} |
487
|
|
|
} else { |
488
|
|
|
return false; |
489
|
|
|
} |
490
|
|
|
} |
491
|
|
|
|
492
|
|
|
private $_latest_tag = null; |
493
|
|
|
|
494
|
|
|
public function getLatestTag() |
|
|
|
|
495
|
|
|
{ |
496
|
|
|
if ($this->_latest_tag === null) { |
497
|
|
|
$git = $this->checkOrSetGitCommsWrapper(); |
498
|
|
|
if ($git) { |
499
|
|
|
$options = array( |
500
|
|
|
'tags' => true, |
501
|
|
|
'simplify-by-decoration' => true, |
502
|
|
|
'pretty' => 'format:%ai %d' |
503
|
|
|
); |
504
|
|
|
|
505
|
|
|
$cwd = getcwd(); |
506
|
|
|
chdir($this->Directory); |
|
|
|
|
507
|
|
|
|
508
|
|
|
try { |
509
|
|
|
$result = $git->log($options); |
510
|
|
|
} catch (Exception $e) { |
511
|
|
|
$errStr = $e->getMessage(); |
512
|
|
|
if (stripos($errStr, 'does not have any commits') === false) { |
513
|
|
|
print_r($e); |
514
|
|
|
throw $e; |
515
|
|
|
} else { |
516
|
|
|
GeneralMethods::output_to_screen('Unable to get tag because there are no commits to the repository'); |
517
|
|
|
return false; |
518
|
|
|
} |
519
|
|
|
} |
520
|
|
|
|
521
|
|
|
|
522
|
|
|
chdir($cwd); |
523
|
|
|
|
524
|
|
|
$resultLines = explode("\n", $result->getOutput()); |
525
|
|
|
|
526
|
|
|
// 2016-10-14 12:29:08 +1300 (HEAD -> master, tag: 2.3.0, tag: 2.2.0, tag: 2.1.0, origin/master, origin/HEAD)\ |
|
|
|
|
527
|
|
|
// or |
528
|
|
|
// 2016-08-29 17:18:22 +1200 (tag: 2.0.0) |
|
|
|
|
529
|
|
|
//print_r($resultLines); |
530
|
|
|
|
531
|
|
|
|
532
|
|
|
if (count($resultLines) == 0) { |
533
|
|
|
return false; |
534
|
|
|
} |
535
|
|
|
|
536
|
|
|
$latestTimeStamp = 0; |
537
|
|
|
$latestTag = false; |
538
|
|
|
foreach ($resultLines as $line) { |
539
|
|
|
$isTagInLine = (strpos($line, 'tag') !== false); |
540
|
|
|
if ($isTagInLine) { |
541
|
|
|
$tagStr = trim(substr($line, 25)); |
542
|
|
|
$dateStr = trim(substr($line, 0, 26)); |
543
|
|
|
|
544
|
|
|
|
545
|
|
|
//extract tag numbers from $tagStr |
546
|
|
|
|
547
|
|
|
$matches = array(); |
548
|
|
|
// print_r ("original!!! " . $tagStr); |
|
|
|
|
549
|
|
|
$result = preg_match_all('/tag: \d{1,3}.\d{1,3}.\d{1,3}/', $tagStr, $matches); |
550
|
|
|
if ($result === false) { |
551
|
|
|
continue; |
552
|
|
|
} elseif ($result > 1) { |
553
|
|
|
$tagStr = $matches[0][0]; |
554
|
|
|
} |
555
|
|
|
//print_r ($matches); |
|
|
|
|
556
|
|
|
|
557
|
|
|
$tagStr = str_replace('(', '', $tagStr); |
558
|
|
|
$tagStr = str_replace(')', '', $tagStr); |
559
|
|
|
$timeStamp = strtotime($dateStr); |
560
|
|
|
|
561
|
|
|
if ($latestTimeStamp < $timeStamp) { |
562
|
|
|
$latestTimeStamp = $timeStamp; |
563
|
|
|
$latestTag = $tagStr; |
564
|
|
|
} |
565
|
|
|
} |
566
|
|
|
} |
567
|
|
|
if (isset($latestTag) && $latestTag) { |
568
|
|
|
$latestTag = str_replace('tag:', '', $latestTag) ; |
569
|
|
|
|
570
|
|
|
|
571
|
|
|
$tagParts = explode('.', $latestTag); |
572
|
|
|
|
573
|
|
|
if (count($tagParts) != 3) { |
574
|
|
|
return false; |
575
|
|
|
} |
576
|
|
|
$this->_latest_tag = array( |
577
|
|
|
'tagstring' => $latestTag, |
578
|
|
|
'tagparts' => $tagParts, |
579
|
|
|
'timestamp' => $latestTimeStamp); |
580
|
|
|
} else { |
581
|
|
|
$this->_latest_tag = false; |
582
|
|
|
} |
583
|
|
|
} |
584
|
|
|
} |
585
|
|
|
return $this->_latest_tag; |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
/** |
589
|
|
|
* git command used: //git log 0.0.1..HEAD --oneline |
590
|
|
|
* return @string (major | minor | patch) |
591
|
|
|
*/ |
592
|
|
|
public function getChangeTypeSinceLastTag() |
593
|
|
|
{ |
594
|
|
|
$latestTag = trim($this->getLatestTag()['tagstring']); |
595
|
|
|
|
596
|
|
|
$git = $this->checkOrSetGitCommsWrapper(); |
597
|
|
|
if ($git) { |
598
|
|
|
|
599
|
|
|
//var_dump ($git); |
|
|
|
|
600
|
|
|
//die(); |
601
|
|
|
|
602
|
|
|
$options = array( |
603
|
|
|
'oneline' => true |
604
|
|
|
); |
605
|
|
|
|
606
|
|
|
$cwd = getcwd(); |
607
|
|
|
chdir($this->Directory); |
|
|
|
|
608
|
|
|
|
609
|
|
|
try { |
610
|
|
|
$result = $git->log($latestTag.'..HEAD', $options); |
611
|
|
|
// print_r($latestTag); |
|
|
|
|
612
|
|
|
// print_r($result); |
|
|
|
|
613
|
|
|
if (!is_array($result)) { |
614
|
|
|
$result = explode("\n", $result); |
615
|
|
|
} |
616
|
|
|
// print_r ($result); |
|
|
|
|
617
|
|
|
} catch (Exception $e) { |
618
|
|
|
$errStr = $e->getMessage(); |
|
|
|
|
619
|
|
|
GeneralMethods::output_to_screen('Unable to get next tag type (getChangeTypeSinceLastTag)'); |
620
|
|
|
return false; |
621
|
|
|
} |
622
|
|
|
|
623
|
|
|
chdir($cwd); |
624
|
|
|
$returnLine = 'PATCH'; |
625
|
|
|
|
626
|
|
|
|
627
|
|
|
|
628
|
|
|
|
629
|
|
|
foreach ($result as $line) { |
630
|
|
|
if (stripos($line, 'MAJOR:') !== false) { |
631
|
|
|
$returnLine = 'MAJOR'; |
632
|
|
|
break; |
633
|
|
|
} |
634
|
|
|
if (stripos($line, 'MINOR:') !== false) { |
635
|
|
|
$returnLine = 'MINOR'; |
636
|
|
|
} |
637
|
|
|
} |
638
|
|
|
return $returnLine; |
639
|
|
|
} |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
public function createTag($tagCommandOptions) |
643
|
|
|
{ |
644
|
|
|
$this->gitRepo->tag($tagCommandOptions); |
645
|
|
|
$this->gitRepo->push(array('tags' => true)); |
646
|
|
|
} |
647
|
|
|
|
648
|
|
|
public function updateGitHubInfo($array) |
649
|
|
|
{ |
650
|
|
|
// see https://developer.github.com/v3/repos/#edit |
651
|
|
|
|
652
|
|
|
# not working |
653
|
|
|
|
654
|
|
|
$defaultValues =array( |
655
|
|
|
'name' => $this->LongModuleName(), |
656
|
|
|
'private' => false, |
657
|
|
|
'has_wiki' => false, |
658
|
|
|
'has_issues' => true, |
659
|
|
|
'has_downloads' => true, |
660
|
|
|
'homepage' => 'http://ssmods.com/' |
661
|
|
|
); |
662
|
|
|
|
663
|
|
|
if ($this->Description) { |
|
|
|
|
664
|
|
|
$array['description'] = $this->Description; |
|
|
|
|
665
|
|
|
} |
666
|
|
|
|
667
|
|
|
foreach ($defaultValues as $key=>$value) { |
668
|
|
|
if (! isset($array[$key])) { |
669
|
|
|
$array[$key] = $value; |
670
|
|
|
} |
671
|
|
|
} |
672
|
|
|
|
673
|
|
|
GeneralMethods::OutputToScreen('updating Git Repo information ...'); |
674
|
|
|
|
675
|
|
|
$this->gitApiCall($array, '', 'PATCH'); |
676
|
|
|
} |
677
|
|
|
|
678
|
|
|
protected function gitApiCall($data, $gitAPIcommand = '', $method = 'GET') |
|
|
|
|
679
|
|
|
{ |
680
|
|
|
$jsonData = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); |
681
|
|
|
GeneralMethods::OutputToScreen('Running Git API command ' .$gitAPIcommand. ' using ' .$method. ' method...'); |
682
|
|
|
$gitUserName = $this->Config()->get('github_user_name'); |
683
|
|
|
$url = 'https://api.github.com/:repos/' . trim($gitUserName) . '/:' . trim($this->ModuleName); |
|
|
|
|
684
|
|
|
if (trim($gitAPIcommand)) { |
685
|
|
|
$url .= '/' . trim($gitAPIcommand); |
686
|
|
|
} |
687
|
|
|
$method = trim(strtoupper($method)); |
688
|
|
|
$ch = curl_init($url); |
689
|
|
|
$header = "Content-Type: application/json"; |
690
|
|
|
if ($method == 'GET') { |
691
|
|
|
$url .= '?'.http_build_query($data); |
692
|
|
|
} |
693
|
|
|
$gitApiUserName = trim($this->Config()->get('git_api_login_username')); |
694
|
|
|
$gitApiUserPassword = trim($this->Config()->get('git_api_login_password')); |
695
|
|
|
$gitApiAccessToken = trim($this->Config()->get('git_personal_access_token')); |
696
|
|
|
if (trim($gitApiAccessToken)) { |
697
|
|
|
$gitApiUserPassword = $gitApiAccessToken; |
698
|
|
|
} |
699
|
|
|
curl_setopt($ch, CURLOPT_VERBOSE, 1); |
700
|
|
|
curl_setopt($ch, CURLOPT_URL, $url); |
701
|
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); |
702
|
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
703
|
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array($header)); |
704
|
|
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); |
705
|
|
|
curl_setopt( |
706
|
|
|
$ch, |
707
|
|
|
CURLOPT_USERAGENT, |
708
|
|
|
'Silverstripe-update-module-module' |
709
|
|
|
); |
710
|
|
|
if (isset($gitApiUserName) && isset($gitApiUserPassword)) { |
711
|
|
|
curl_setopt($ch, CURLOPT_USERPWD, $gitApiUserName . ':' . $gitApiUserPassword); |
712
|
|
|
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); |
713
|
|
|
} |
714
|
|
|
if ($method == 'POST') { |
715
|
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData); |
716
|
|
|
} |
717
|
|
|
$curlResult = curl_exec($ch); |
718
|
|
|
if (! $curlResult) { |
719
|
|
|
$msg = "curl exectution failed"; |
720
|
|
|
GeneralMethods::outputToScreen($msg); |
721
|
|
|
UpdateModules::$unsolvedItems["none"] = $msg; |
722
|
|
|
} |
723
|
|
|
print_r($url); |
724
|
|
|
print_r('<br/>'); |
725
|
|
|
print_r($curlResult); |
726
|
|
|
die(); |
|
|
|
|
727
|
|
|
return $curlResult; |
|
|
|
|
728
|
|
|
} |
729
|
|
|
|
730
|
|
|
|
731
|
|
|
public function addRepoToScrutinzer() |
732
|
|
|
{ |
733
|
|
|
if (! trim($this->Config()->get('scrutinizer_api_key'))) { |
734
|
|
|
GeneralMethods::outputToScreen("<li> not Scrutinizer API key set </li>"); |
735
|
|
|
return false; |
736
|
|
|
} |
737
|
|
|
|
738
|
|
|
//see https://scrutinizer-ci.com/docs/api/#repositories |
739
|
|
|
$scrutinizerApiPath = "https://scrutinizer-ci.com/api"; |
740
|
|
|
$endPoint = "repositories/g?access_token=" . trim($this->Config()->get('scrutinizer_api_key')); |
741
|
|
|
$url = $scrutinizerApiPath . "/" . $endPoint; |
742
|
|
|
$username = $this->Config()->get('github_user_name'); |
743
|
|
|
$repoName = $username.'/'.$this->ModuleName; |
|
|
|
|
744
|
|
|
|
745
|
|
|
|
746
|
|
|
$postFields = array( |
747
|
|
|
'name' => $repoName, |
748
|
|
|
); |
749
|
|
|
|
750
|
|
|
$ch = curl_init($url); |
751
|
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); |
752
|
|
|
|
753
|
|
|
curl_setopt($ch, CURLOPT_URL, $url); |
754
|
|
|
curl_setopt($ch, CURLOPT_POST, count($postFields)); |
755
|
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
756
|
|
|
|
757
|
|
|
|
758
|
|
|
$curlResult = curl_exec($ch); |
759
|
|
|
|
760
|
|
|
if (! $curlResult) { |
761
|
|
|
GeneralMethods::outputToScreen("<li> could not add $repoName to Scrutinizer ... </li>"); |
762
|
|
|
//UpdateModules::$unsolvedItems[$repoName] = "Could not add $reopName to Scrutiniser (curl failure)"; |
|
|
|
|
763
|
|
|
|
764
|
|
|
UpdateModules::addUnsolvedProblem($repoName, "Could not add $repoName to Scrutiniser (curl failure)"); |
765
|
|
|
|
766
|
|
|
return false; |
767
|
|
|
} |
768
|
|
|
|
769
|
|
|
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); |
770
|
|
|
|
771
|
|
|
|
772
|
|
|
if ($httpcode == 201) { |
773
|
|
|
GeneralMethods::outputToScreen("<li> Added $repoName to Scrutinizer ... </li>"); |
774
|
|
|
} else { |
775
|
|
|
GeneralMethods::outputToScreen("<li> could not add $repoName to Scrutinizer ... </li>"); |
776
|
|
|
//UpdateModules::$unsolvedItems[$repoName] = "Could not add $reopName to Scrutiniser (HttpCode $httpcode)"; |
|
|
|
|
777
|
|
|
UpdateModules::addUnsolvedProblem($repoName, "Could not add $repoName to Scrutiniser (HttpCode $httpcode)"); |
778
|
|
|
} |
779
|
|
|
} |
780
|
|
|
} |
781
|
|
|
|
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.